curvedLines.js ➔ init   F
last analyzed

Complexity

Conditions 26

Size

Total Lines 206
Code Lines 127

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 127
dl 0
loc 206
rs 0
c 0
b 0
f 0
cc 26

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like curvedLines.js ➔ init often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* The MIT License
2
3
 Copyright (c) 2011 by Michael Zinsmaier and nergal.dev
4
 Copyright (c) 2012 by Thomas Ritou
5
6
 Permission is hereby granted, free of charge, to any person obtaining a copy
7
 of this software and associated documentation files (the "Software"), to deal
8
 in the Software without restriction, including without limitation the rights
9
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 copies of the Software, and to permit persons to whom the Software is
11
 furnished to do so, subject to the following conditions:
12
13
 The above copyright notice and this permission notice shall be included in
14
 all copies or substantial portions of the Software.
15
16
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 THE SOFTWARE.
23
 */
24
25
/*
26
27
 ____________________________________________________
28
29
 what it is:
30
 ____________________________________________________
31
32
 curvedLines is a plugin for flot, that tries to display lines in a smoother way.
33
 The plugin is based on nergal.dev's work https://code.google.com/p/flot/issues/detail?id=226
34
 and further extended with a mode that forces the min/max points of the curves to be on the
35
 points. Both modes are achieved through adding of more data points
36
 => 1) with large data sets you may get trouble
37
 => 2) if you want to display the points too, you have to plot them as 2nd data series over the lines
38
39
 && 3) consecutive x data points are not allowed to have the same value
40
41
 This is version 0.5 of curvedLines so it will probably not work in every case. However
42
 the basic form of use descirbed next works (:
43
44
 Feel free to further improve the code
45
46
 ____________________________________________________
47
48
 how to use it:
49
 ____________________________________________________
50
51
 var d1 = [[5,5],[7,3],[9,12]];
52
53
 var options = { series: { curvedLines: {  active: true }}};
54
55
 $.plot($("#placeholder"), [{data = d1, lines: { show: true}, curvedLines: {apply: true}}], options);
56
57
 _____________________________________________________
58
59
 options:
60
 _____________________________________________________
61
62
 active:           bool true => plugin can be used
63
 apply:            bool true => series will be drawn as curved line
64
 fit:              bool true => forces the max,mins of the curve to be on the datapoints
65
 curvePointFactor  int  defines how many "virtual" points are used per "real" data point to
66
 emulate the curvedLines (points total = real points * curvePointFactor)
67
 fitPointDist:     int  defines the x axis distance of the additional two points that are used
68
 to enforce the min max condition.
69
70
 + line options (since v0.5 curved lines use flots line implementation for drawing
71
 => line options like fill, show ... are supported out of the box)
72
73
 */
74
75
/*
76
 *  v0.1   initial commit
77
 *  v0.15  negative values should work now (outcommented a negative -> 0 hook hope it does no harm)
78
 *  v0.2   added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi)
79
 *  v0.3   improved saddle handling and added basic handling of Dates
80
 *  v0.4   rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug
81
 *  v0.5   rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou).
82
 * 		   This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill,
83
 * 	       shadow) are now supported out of the box
84
 *  v0.6   flot 0.8 compatibility and some bug fixes
85
 */
86
87
(function($) {
88
89
    var options = {
90
        series : {
91
            curvedLines : {
92
                active : false,
93
                apply: false,
94
                fit : false,
95
                curvePointFactor : 20,
96
                fitPointDist : undefined
97
            }
98
        }
99
    };
100
101
    function init(plot) {
102
103
        plot.hooks.processOptions.push(processOptions);
104
105
        //if the plugin is active register processDatapoints method
106
        function processOptions(plot, options) {
107
            if (options.series.curvedLines.active) {
108
                plot.hooks.processDatapoints.unshift(processDatapoints);
109
            }
110
        }
111
112
        //only if the plugin is active
113
        function processDatapoints(plot, series, datapoints) {
114
            var nrPoints = datapoints.points.length / datapoints.pointsize;
115
            var EPSILON = 0.5; //pretty large epsilon but save
116
117
            if (series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) {
118
                if (series.lines.fill) {
119
120
                    var pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1)
121
                        ,pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2); //flot makes sure for us that we've got a second y point if fill is true !
122
123
                    //Merge top and bottom curve
124
                    datapoints.pointsize = 3;
125
                    datapoints.points = [];
126
                    var j = 0;
127
                    var k = 0;
128
                    var i = 0;
129
                    var ps = 2;
130
                    while (i < pointsTop.length || j < pointsBottom.length) {
131
                        if (pointsTop[i] == pointsBottom[j]) {
132
                            datapoints.points[k] = pointsTop[i];
133
                            datapoints.points[k + 1] = pointsTop[i + 1];
134
                            datapoints.points[k + 2] = pointsBottom[j + 1];
135
                            j += ps;
136
                            i += ps;
137
138
                        } else if (pointsTop[i] < pointsBottom[j]) {
139
                            datapoints.points[k] = pointsTop[i];
140
                            datapoints.points[k + 1] = pointsTop[i + 1];
141
                            datapoints.points[k + 2] = k > 0 ? datapoints.points[k-1] : null;
142
                            i += ps;
143
                        } else {
144
                            datapoints.points[k] = pointsBottom[j];
145
                            datapoints.points[k + 1] = k > 1 ? datapoints.points[k-2] : null;
146
                            datapoints.points[k + 2] = pointsBottom[j + 1];
147
                            j += ps;
148
                        }
149
                        k += 3;
150
                    }
151
                } else if (series.lines.lineWidth > 0) {
152
                    datapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1);
153
                    datapoints.pointsize = 2;
154
                }
155
            }
156
        }
157
158
        //no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226
159
        //if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code.
160
        function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) {
161
162
            var points = datapoints.points, ps = datapoints.pointsize;
163
            var num = curvedLinesOptions.curvePointFactor * (points.length / ps);
164
165
            var xdata = new Array;
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
166
            var ydata = new Array;
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
167
168
            var curX = -1;
0 ignored issues
show
Unused Code introduced by
The assignment to variable curX seems to be never used. Consider removing it.
Loading history...
169
            var curY = -1;
0 ignored issues
show
Unused Code introduced by
The assignment to variable curY seems to be never used. Consider removing it.
Loading history...
170
            var j = 0;
171
172
            if (curvedLinesOptions.fit) {
173
                //insert a point before and after the "real" data point to force the line
174
                //to have a max,min at the data point.
175
176
                var fpDist;
177
                if(typeof curvedLinesOptions.fitPointDist == 'undefined') {
178
                    //estimate it
179
                    var minX = points[0];
180
                    var maxX = points[points.length-ps];
181
                    fpDist = (maxX - minX) / (500 * 100); //x range / (estimated pixel length of placeholder * factor)
182
                } else {
183
                    //use user defined value
184
                    fpDist = curvedLinesOptions.fitPointDist;
185
                }
186
187
                for (var i = 0; i < points.length; i += ps) {
188
189
                    var frontX;
190
                    var backX;
191
                    curX = i;
192
                    curY = i + yPos;
193
194
                    //add point X s
195
                    frontX = points[curX] - fpDist;
196
                    backX = points[curX] + fpDist;
197
198
                    var factor = 2;
199
                    while (frontX == points[curX] || backX == points[curX]) {
200
                        //inside the ulp
201
                        frontX = points[curX] - (fpDist * factor);
202
                        backX = points[curX] + (fpDist * factor);
203
                        factor++;
204
                    }
205
206
                    //add curve points
207
                    xdata[j] = frontX;
208
                    ydata[j] = points[curY];
209
                    j++;
210
211
                    xdata[j] = points[curX];
212
                    ydata[j] = points[curY];
213
                    j++;
214
215
                    xdata[j] = backX;
216
                    ydata[j] = points[curY];
217
                    j++;
218
                }
219
            } else {
220
                //just use the datapoints
221
                for (var i = 0; i < points.length; i += ps) {
222
                    curX = i;
223
                    curY = i + yPos;
224
225
                    xdata[j] = points[curX];
226
                    ydata[j] = points[curY];
227
                    j++;
228
                }
229
            }
230
231
            var n = xdata.length;
232
233
            var y2 = new Array();
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
234
            var delta = new Array();
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
235
            y2[0] = 0;
236
            y2[n - 1] = 0;
237
            delta[0] = 0;
238
239
            for (var i = 1; i < n - 1; ++i) {
240
                var d = (xdata[i + 1] - xdata[i - 1]);
241
                if (d == 0) {
242
                    //point before current point and after current point need some space in between
243
                    return [];
244
                }
245
246
                var s = (xdata[i] - xdata[i - 1]) / d;
247
                var p = s * y2[i - 1] + 2;
248
                y2[i] = (s - 1) / p;
249
                delta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]);
250
                delta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p;
251
            }
252
253
            for (var j = n - 2; j >= 0; --j) {
254
                y2[j] = y2[j] * y2[j + 1] + delta[j];
255
            }
256
257
            //   xmax  - xmin  / #points
258
            var step = (xdata[n - 1] - xdata[0]) / (num - 1);
259
260
            var xnew = new Array;
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
261
            var ynew = new Array;
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
262
            var result = new Array;
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
263
264
            xnew[0] = xdata[0];
265
            ynew[0] = ydata[0];
266
267
            result.push(xnew[0]);
268
            result.push(ynew[0]);
269
270
            for ( j = 1; j < num; ++j) {
271
                //new x point (sampling point for the created curve)
272
                xnew[j] = xnew[0] + j * step;
273
274
                var max = n - 1;
275
                var min = 0;
276
277
                while (max - min > 1) {
278
                    var k = Math.round((max + min) / 2);
279
                    if (xdata[k] > xnew[j]) {
280
                        max = k;
281
                    } else {
282
                        min = k;
283
                    }
284
                }
285
286
                //found point one to the left and one to the right of generated new point
287
                var h = (xdata[max] - xdata[min]);
288
289
                if (h == 0) {
290
                    //similar to above two points from original x data need some space between them
291
                    return [];
292
                }
293
294
                var a = (xdata[max] - xnew[j]) / h;
295
                var b = (xnew[j] - xdata[min]) / h;
296
297
                ynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6;
298
299
                result.push(xnew[j]);
300
                result.push(ynew[j]);
301
            }
302
303
            return result;
304
        }
305
306
    }//end init
307
308
    $.plot.plugins.push({
309
        init : init,
310
        options : options,
311
        name : 'curvedLines',
312
        version : '0.5'
313
    });
314
315
})(jQuery);
316